package beat

import (
	"log"
	"math/rand"
	"sort"
)

type ThreatOne struct {
	TargetId int32
	Value    float32
}

type ThreatList struct {
	List     []int32           //value is targetId, one.TargetId, sorted by one.Value asc
	ValueMap map[int32]float32 //map[one.TargetId]one.Value

	recvQ  chan Dmg // who beared //TODO should not rely on Dmg. use ThreatMsg{int,float32} instead
	done   chan bool
	closed bool
}

func NewThreatList() *ThreatList {
	list := &ThreatList{
		List:     make([]int32, 0),
		ValueMap: make(map[int32]float32, 0),
		recvQ:    make(chan Dmg, 1),
		done:     make(chan bool),
	}
	return list
}

func (t *ThreatList) GetTop(n int) (targetId int32) {
	if len(t.List) == 0 {
		return -1
	}
	if n >= len(t.List) {
		return t.List[len(t.List)-1]
	}

	return t.List[n]
}

func (t *ThreatList) GetRandom() (targetidx int32) {
	if len(t.List) == 0 {
		return -1
	}
	randIdx := rand.Int() % len(t.List)
	return t.List[randIdx]
}

func (t *ThreatList) Serve() {
	for {
		select {
		case d := <-t.recvQ:
			//TODO if someone die, kick out
			switch d.T {
			case DmgTypeDie:
				t.kickOne(d.From)
			default:
				//from hurt bot, or heal hostile
				t.pushIn(ThreatOne{TargetId: d.From, Value: d.GetBeared() * d.Tx})
			}
		case <-t.done:
			t.closed = true
			return
		}
	}
}

func (t *ThreatList) Bear(d Dmg) {
	if t.closed {
		return
	}
	go func() {
		t.recvQ <- d
	}()
}

func (t *ThreatList) Shutdown() {
	if t.closed == false {
		close(t.done)
	}
}

//将一个对象放入threatList,并按Value排序。不会有延迟，瞬时完成
func (t *ThreatList) pushIn(one ThreatOne) {
	//方案1、看one.TargetId在map是否存在:不存在则更新map，插入List；存在则删除List中原位置，并找到新位置，插入新位置，更新map
	//方案2、看one.TargetId在map是否存在:不存在则更新map，插入List；存在则更新List，并对List重新排序
	if len(t.List) == 0 {
		t.List = make([]int32, 1)
		t.List[0] = one.TargetId
		t.ValueMap[one.TargetId] = one.Value
		return
	}

	if _, exist := t.ValueMap[one.TargetId]; exist {
		t.ValueMap[one.TargetId] += one.Value
		if len(t.List) > 1 {
			t.Sort()
		}
		log.Printf("one:%v in list:%v %v", one, t.List, t.ValueMap)
	} else {
		expectIdx := t.findByValue(one)
		if expectIdx == len(t.List) {
			t.List = append(t.List, one.TargetId)
		} else if expectIdx == 0 {
			t.List = append([]int32{one.TargetId}, t.List...)
		} else {

			tmpList := make([]int32, len(t.List)+1)
			for i := 0; i < len(t.List); i++ {
				if i < expectIdx {
					tmpList[i] = t.List[i]
				} else if i == expectIdx {
					tmpList[i] = one.TargetId
					tmpList[i+1] = t.List[i]
				} else {
					tmpList[i+1] = t.List[i]
				}
			}
			t.List = tmpList
		}
		t.ValueMap[one.TargetId] = one.Value
		log.Printf("one:%v expectedIdx:%d list:%v %v", one, expectIdx, t.List, t.ValueMap) //will panic when format
	}
}

//kickOne和pushIn在不同的协程中，有并发问题，需要加锁，或者放入同一个协程执行
func (t *ThreatList) kickOne(targetId int32) {
	// log.Printf("try kick %d, list:%v map:%v", targetId, t.List, t.ValueMap)
	if _, exist := t.ValueMap[targetId]; exist {
		expectedIdx := t.findByValue(ThreatOne{TargetId: targetId, Value: t.ValueMap[targetId]})

		//kick one
		tmpList := t.List[:expectedIdx]
		tmpList = append(tmpList, t.List[expectedIdx+1:]...)
		t.List = tmpList
		delete(t.ValueMap, targetId)
		// log.Printf("after kick %d, list:%v map:%v", targetId, t.List, t.ValueMap)
	}
}

//idx 在t.List中不是有序的 而List中是Value有序的
// func (t *ThreatList) findByIdx(one ThreatOne) int {
// 	//t.List must be sorted by one.Value asc
// 	// sort.SearchInts(a []int, x int)
// 	return sort.Search(len(t.List), func(i int) bool {
// 		return t.List[i] == one.TargetId
// 	})
// }
func (t *ThreatList) findByValue(one ThreatOne) int {
	//t.List must be sorted by one.Value asc
	return sort.Search(len(t.List), func(i int) bool {
		return t.ValueMap[t.List[i]] <= one.Value
	})
}

func (t *ThreatList) Sort() {
	sort.Slice(t.List, func(i, j int) bool {
		return t.ValueMap[t.List[i]] >= t.ValueMap[t.List[j]]
	})
}
